using CfgTable;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.GamePlay;
using NetProtocol.Enum;
using NetProtocol.POD;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    public static class QuestExts
    {
        /** 是否是组合类型目标 -- 父子任务 */
        public static bool IsGroupTarget(this QuestTargetType targetType)
        {
            return (int)targetType < 20;
        }

        /** 是否是数据型目标 */
        public static bool IsDataTarget(this QuestTargetType targetType)
        {
            int v = (int)targetType / 10_0000;
            return v == 2;
        }

        /** 是否是事件型目标 */
        public static bool IsEventTarget(this QuestTargetType targetType)
        {
            int v = (int)targetType / 10_0000;
            return v == 1;
        }

    }

    /// <summary>
    /// 目标类型由6位构成（十万），
    /// 最高位（十万位）为1表示Game服目标，为2表示Logic服目标(关卡内目标)，
    /// 次高位（万位）为1表示按条件完成任务（累计触发式），比如：累积签到N天；为2表示根据玩家当前数据完成，比如：升到多少级。
    /// </summary>
    public class LogicQuestModule
    {
        public static LogicQuestModule Instance { get; } = new LogicQuestModule();
        private readonly ListPoolImpl<LogicQuestData> questListPool = new ListPoolImpl<LogicQuestData>(2);
        private readonly ListPoolImpl<CfgQuest> cfgListPool = new ListPoolImpl<CfgQuest>(2);

        private bool fromDataSyncEvent = false;

        #region 数据同步

        public void SyncEvent_AddQuest(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            List<LogicQuestData> quests = questListPool.Get();
            foreach (QuestPOD questPod in eventPod.quests)
            {
                quests.Add(LogicQuestData.CreateFromPOD(questPod));
            }
            try
            {
                fromDataSyncEvent = true;
                AcceptQuestImpl(logicPlayer, quests);
            }
            finally
            {
                fromDataSyncEvent = false;
                questListPool.Put(quests);
            }
        }

        public void SyncEvent_UpdateQuest(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (QuestPOD questPod in eventPod.quests)
            {
                if (logicPlayer.currentQuests.TryGetValue(questPod.cid, out var quest))
                {
                    quest.SyncData(questPod);
                }
            }
        }

        public void SyncEvent_UpdateProgress(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (KeyValuePair<int, int> pair in eventPod.dicParams)
            {
                if (logicPlayer.currentQuests.TryGetValue(pair.Key, out var questData))
                {
                    questData.progress = pair.Value;
                }
            }
        }

        public void SyncEvent_DelQuest(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            fromDataSyncEvent = true;
            try
            {
                foreach (int questCid in eventPod.intParams)
                {
                    RemoveQuest(logicPlayer, questCid);
                }
            }
            finally
            {
                fromDataSyncEvent = false;
            }
        }

        public void SyncEvent_AddCommittedQuests(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (KeyValuePair<int, int> pair in eventPod.dicParams)
            {
                logicPlayer.committedQuests[pair.Key] = pair.Value;
            }
        }

        public void SyncEvent_DelCommittedQuests(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (int questCid in eventPod.intParams)
            {
                logicPlayer.committedQuests.Remove(questCid);
            }
        }

        public void SyncEvent_AddFailedQuests(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (int questCid in eventPod.intParams)
            {
                logicPlayer.failedQuests.Add(questCid);
            }
        }

        public void SyncEvent_DelFailedQuests(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (int questCid in eventPod.intParams)
            {
                logicPlayer.failedQuests.Remove(questCid);
            }
        }

        public void SyncEvent_UpdateTrackQuest(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            int questCid = eventPod.intParams[0];
            logicPlayer.trackQuestCid = questCid;
            logicPlayer.levelPlayer.RefreshTrackQuestTargetEntity();
        }

        #endregion

        #region api

        #region accept

        /// <summary>
        /// 接取任务
        /// </summary>
        /// <param name="logicPlayer">玩家</param>
        /// <param name="questCid">任务cid</param>
        /// <returns>是否成功</returns>
        public bool AcceptQuest(LogicPlayer logicPlayer, int questCid)
        {
            CfgQuest cfgQuest = TableCenter.quest.Get(questCid);
            if (cfgQuest == null)
            {
                return false;
            }
            if (logicPlayer.currentQuests.ContainsKey(questCid))
            {
                return false;
            }
            if (logicPlayer.committedQuests.ContainsKey(questCid))
            {
                return false;
            }
            // TODO 需要测试时间段

            LogicQuestData parent = null;
            if (TableCenter.quest.child2ParentMap.TryGetValue(questCid, out int parentCid))
            {
                if (!logicPlayer.currentQuests.TryGetValue(parentCid, out parent))
                {
                    throw new Exception("parent quest is absent, curQuestCid: " + questCid);
                }
            }

            List<LogicQuestData> outList = new List<LogicQuestData>(2);
            CreateQuest(logicPlayer, questCid, outList, parent);
            AcceptQuestImpl(logicPlayer, outList);
            return true;
        }

        private void CreateQuest(LogicPlayer logicPlayer, int cid, List<LogicQuestData> outList, LogicQuestData parentQuest)
        {
            CfgQuest cfg = TableCenter.quest.Get(cid);
            if (cfg == null)
            {
                return;
            }
            LogicQuestData questData = LogicQuestData.Create(cfg);
            // 继承数据
            int initProgress = 0;
            if (cfg.IsInherit && logicPlayer.committedQuests.TryGetValue(cfg.PreQuest, out int oldProgress))
            {
                initProgress = oldProgress;
            }
            initProgress = Math.Max(initProgress, cfg.InitNum);
            questData.progress = initProgress;
            if (parentQuest != null)
            {
                questData.parentCid = parentQuest.cid;
            }
            outList.Add(questData);

            // 创建子任务
            switch (cfg.TargetType)
            {
                case QuestTargetType.Sequence:
                case QuestTargetType.Repeat:
                    {
                        // 顺序执行，初始接取一个
                        int childQuestCid = cfg.ChildQuests[0];
                        CreateQuest(logicPlayer, childQuestCid, outList, questData);
                        break;
                    }
                case QuestTargetType.Switch:
                    {
                        // 根据玩家的属性，选择一个接取
                        bool success = false;
                        for (int i = 0; i < cfg.ChildQuests.Count; i++)
                        {
                            int childQuestCid = cfg.ChildQuests[i];
                            if (TestAutoAcceptCondition(logicPlayer, childQuestCid))
                            {
                                success = true;
                                CreateQuest(logicPlayer, childQuestCid, outList, questData);
                                break;
                            }
                        }
                        if (!success)
                        {
                            throw new Exception("switch select child failed");
                        }
                        break;
                    }
                case QuestTargetType.JoinAll:
                case QuestTargetType.JoinAny:
                case QuestTargetType.JoinMany:
                    {
                        // 并行任务，初始全部接取
                        for (int i = 0; i < cfg.ChildQuests.Count; i++)
                        {
                            int childQuestCid = cfg.ChildQuests[i];
                            CreateQuest(logicPlayer, childQuestCid, outList, questData);
                        }
                        break;
                    }
            }
        }

        private bool TestAutoAcceptCondition(LogicPlayer logicPlayer, int questCid)
        {
            CfgQuest questCfg = TableCenter.quest.Get(questCid);
            if (questCfg.AutoAcceptCondId == 0)
            {
                return true;
            }
            if (questCfg.AutoAcceptCondId == -1)
            {
                return false;
            }
            // TODO 测试具体条件
            return true;
        }

        private void AcceptQuestImpl(LogicPlayer logicPlayer, List<LogicQuestData> questList)
        {
            foreach (LogicQuestData quest in questList)
            {
                logicPlayer.currentQuests.Add(quest.cid, quest); // 该抛异常抛异常
                UpdateDataTargets(logicPlayer, quest); // 由Game服检测自动提交
            }
            if (!fromDataSyncEvent)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.AddQuest,
                };
                foreach (LogicQuestData questData in questList)
                {
                    eventPod.quests.Add(questData.ToPOD());
                }
                LogicDataSyncModule.Instance.Push(logicPlayer, eventPod);
            }
            // 接取任务的道具由game服发放
        }

        #endregion

        #region update

        private bool UpdateQuestProgress(LogicPlayer player, LogicQuestData questData, int progress)
        {
            if (progress < 0)
            {
                throw new ArgumentException($"progress: {progress} < 0");
            }
            if (questData.progress == progress)
            {
                return false;
            }
            if (!questData.IsActive(LogicHelper.TimeNow))
            {
                return false;
            }
            questData.progress = progress;
            // 任务状态不可逆时，自动进入完成状态 -- 此后不再更新进度
            if (questData.isProgressMet && CanAutoFinish(questData))
            {
                questData.status = QuestStatus.Finished;
                if (!fromDataSyncEvent)
                {
                    SyncQuestToGameServer(player, questData);
                }
            }
            else
            {
                // 特定优化，只同步进度
                if (!fromDataSyncEvent)
                {
                    LogicDataSyncModule.Instance.Push(player, new DataSyncEventPOD()
                    {
                        type = DataSyncType.UpdateQuestProgress,
                        dicParams = { { questData.cid, progress } }
                    });
                }
            }
            // 由Game服检测自动提交
            return true;
        }

        private bool CanAutoFinish(LogicQuestData questData)
        {
            if (questData.hasParent)
            {
                return true; // 子任务自动完成
            }
            return questData.cfg.Type != QuestType.Achieve
                   && !questData.cfg.ChangeStatus;
        }

        /** 将任务标记为失败 -- 注意，此时仍然挂在角色身上，在give-up时才加入到历史失败列表 */
        private void SetFailed(LogicPlayer player, LogicQuestData questData)
        {
            if (questData.status == QuestStatus.Committed)
            {
                throw new ArgumentException("Committed");
            }
            questData.status = QuestStatus.Failed;
            if (!fromDataSyncEvent)
            {
                SyncQuestToGameServer(player, questData);
            }

            // 通知父节点
            if (questData.hasParent)
            {
                LogicQuestData parentQuest = player.currentQuests[questData.parentCid];
                OnChildQuestCompleted(player, parentQuest, questData);
            }
        }

        private void SyncQuestToGameServer(LogicPlayer player, LogicQuestData quest)
        {
            DataSyncEventPOD eventPod = new DataSyncEventPOD()
            {
                type = DataSyncType.UpdateQuest,
            };
            eventPod.quests.Add(quest.ToPOD());
            LogicDataSyncModule.Instance.Push(player, eventPod);
        }

        #endregion

        /// <summary>
        /// 可能需要提交参数
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="cid"></param>
        /// <param name="arg">提交参数</param>
        public void CommitQuest(LogicPlayer logicPlayer, int cid, int arg = 0)
        {
            // TODO 发送到Game服
        }

        #endregion

        #region 子任务完成事件

        private void OnChildQuestCompleted(LogicPlayer player, LogicQuestData quest, LogicQuestData childQuest)
        {
            if (!quest.IsActive(LogicHelper.TimeNow))
            {
                return;
            }
            // 子任务状态总是存储，更安全
            quest.childStatusMap[childQuest.cid] = (int)childQuest.status;
            if (!fromDataSyncEvent)
            {
                SyncQuestToGameServer(player, quest);
            }

            CfgQuest questCfg = quest.cfg;
            switch (questCfg.TargetType)
            {
                case QuestTargetType.Sequence:
                    {
                        Handler_Sequence(player, quest, childQuest);
                        break;
                    }
                case QuestTargetType.Switch:
                    {
                        // 子任务失败则失败，成功则成功
                        if (childQuest.isFailed)
                        {
                            SetFailed(player, quest);
                        }
                        else
                        {
                            UpdateQuestProgress(player, quest, 1);
                        }
                        break;
                    }
                case QuestTargetType.Repeat:
                    {
                        // 子任务失败则重复接取，成功则进度加1
                        if (childQuest.isFailed)
                        {
                            RemoveQuest(player, childQuest.cid);
                            AcceptQuest(player, childQuest.cid);
                        }
                        else
                        {
                            UpdateQuestProgress(player, quest, quest.progress + 1);
                        }
                        break;
                    }
                case QuestTargetType.JoinAll:
                    {
                        if (childQuest.isFailed)
                        {
                            SetFailed(player, quest);
                            break;
                        }
                        // 如果策划配置的总进度数大于1，则表示策划期望每完成一次进度加1
                        if (questCfg.TargetNum > 1)
                        {
                            UpdateQuestProgress(player, quest, quest.childStatusMap.Count);
                        }
                        else if (quest.childStatusMap.Count >= questCfg.ChildQuests.Count)
                        {
                            UpdateQuestProgress(player, quest, 1);
                        }
                        break;
                    }
                case QuestTargetType.JoinAny:
                    {
                        if (childQuest.isCommitted)
                        {
                            UpdateQuestProgress(player, quest, 1);
                            break;
                        }
                        // 检测全部失败
                        if (quest.childStatusMap.Count >= questCfg.ChildQuests.Count)
                        {
                            SetFailed(player, quest);
                        }
                        break;
                    }
                case QuestTargetType.JoinMany:
                    {
                        Handler_Join_Many(player, quest, childQuest);
                        break;
                    }
            }
        }

        private void Handler_Join_Many(LogicPlayer player, LogicQuestData quest, LogicQuestData childQuest)
        {
            CfgQuest questCfg = quest.cfg;
            int required = questCfg.TargetParams[0]; // 要求完成X个
            int sequence = questCfg.TargetParams[1]; // 前Y个必须成功
            if (quest.CountCommittedChild() >= required
                && quest.CountSequencedCommittedChild() >= sequence)
            {
                UpdateQuestProgress(player, quest, questCfg.TargetNum);
                return;
            }
            if (quest.childStatusMap.Count >= questCfg.ChildQuests.Count)
            {
                SetFailed(player, quest);
                return;
            }
            if (sequence == 0 && questCfg.TargetNum > 1)
            {
                // sequence为0的情况下可以每完成一个进度加1
                UpdateQuestProgress(player, quest, quest.CountCommittedChild());
            }
        }

        private void Handler_Sequence(LogicPlayer player, LogicQuestData quest, LogicQuestData childQuest)
        {
            if (childQuest.isFailed)
            {
                SetFailed(player, quest);
                return;
            }
            // 如果策划配置的总进度数大于1，则表示策划期望每完成一次进度加1
            CfgQuest questCfg = quest.cfg;
            if (questCfg.TargetNum > 1)
            {
                UpdateQuestProgress(player, quest, quest.childStatusMap.Count);
            }
            else if (quest.childStatusMap.Count >= questCfg.ChildQuests.Count)
            {
                UpdateQuestProgress(player, quest, 1);
            }
            if (quest.isFinished)
            {
                return;
            }
            // 自动接取下一个子任务
            int index = questCfg.ChildQuests.IndexOf(childQuest.cid);
            int nextQuestCid = questCfg.ChildQuests[index + 1];
            AcceptQuest(player, nextQuestCid);
        }

        #endregion

        #region remove

        public List<LogicQuestData> RemoveQuest(LogicPlayer player, int cid)
        {
            if (!player.currentQuests.Remove(cid, out LogicQuestData quest))
            {
                return new List<LogicQuestData>();
            }
            List<LogicQuestData> deletedQuests = new List<LogicQuestData>();
            deletedQuests.Add(quest);
            // 删除关联子任务
            {
                List<CfgQuest> childQuestCfgs = cfgListPool.Get();
                GetAllChildQuests(quest.cfg, childQuestCfgs);
                foreach (CfgQuest childQuestCfg in childQuestCfgs)
                {
                    if (player.currentQuests.Remove(childQuestCfg.Id, out LogicQuestData childQuest))
                    {
                        deletedQuests.Add(childQuest);
                    }
                }
                cfgListPool.Put(childQuestCfgs);
            }
            // 同步
            if (!fromDataSyncEvent)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.DelQuest,
                };
                foreach (LogicQuestData deletedQuest in deletedQuests)
                {
                    eventPod.intParams.Add(deletedQuest.cid);
                }
                LogicDataSyncModule.Instance.Push(player, eventPod);
            }
            // 删除道具也由game服删除
            return deletedQuests;
        }

        #endregion

        #region 条件检查

        /// <summary>
        /// 任务是否可以接取
        /// </summary>
        public bool IsAcceptable(LogicPlayer logicPlayer, int questCid, LevelEntity curEntity = null)
        {
            if (logicPlayer.currentQuests.ContainsKey(questCid))
            {
                return false;
            }
            CfgQuest cfg = TableCenter.quest.Get(questCid);
            if (cfg == null) return false;

            // 非重复任务不可重复接取
            if (!cfg.IsRepeat)
            {
                if (logicPlayer.committedQuests.ContainsKey(questCid)
                    || logicPlayer.failedQuests.Contains(questCid))
                {
                    return false;
                }
            }

            if (!cfg.ManualAcceptable) return false;
            // TODO 测试功能开启
            if (cfg.FunctionOpen > 0)
            {
                return false;
            }
            if (cfg.PreQuest > 0 && !logicPlayer.committedQuests.ContainsKey(cfg.PreQuest))
            {
                return false;
            }
            var result = ConditionLevelLogicUtil.Check(cfg.ManualCondition, logicPlayer.levelPlayer.region, logicPlayer.levelPlayer, curEntity);
            return result.Item1;
        }

        /// <summary>
        /// 检测任务目标
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="targetType">目标类型</param>
        /// <param name="targetParams">目标参数，null等同空列表</param>
        /// <param name="num">增加的进度</param>
        public void CheckTarget(LogicPlayer logicPlayer, QuestTargetType targetType, IList<int> targetParams, int num = 1)
        {
            if (targetParams == null)
            {
                targetParams = Array.Empty<int>();
            }
            if (targetType.IsGroupTarget())
            {
                return; // 暂不走这里
            }
            else if (targetType.IsDataTarget())
            {
                foreach (LogicQuestData questData in logicPlayer.currentQuests.Values)
                {
                    if (questData.cfg.TargetType != targetType)
                    {
                        continue;
                    }
                    UpdateDataTargets(logicPlayer, questData);
                }
            }
            else
            {
                foreach (LogicQuestData questData in logicPlayer.currentQuests.Values)
                {
                    if (questData.cfg.TargetType != targetType)
                    {
                        continue;
                    }
                    UpdateEventTargets(logicPlayer, questData, targetParams, num);
                }
            }
        }

        /// <summary>
        /// 更新数据型目标
        /// </summary>
        private bool UpdateDataTargets(LogicPlayer logicPlayer, LogicQuestData questData)
        {
            // TODO 关卡条件
            switch (questData.cfg.TargetType)
            {
            }
            return false;
        }

        /// <summary>
        /// 更新事件型目标
        /// </summary>
        private bool UpdateEventTargets(LogicPlayer logicPlayer, LogicQuestData questData, IList<int> targetParams, int addNum = 1)
        {
            IReadOnlyList<int> cfgParams = questData.cfg.TargetParams;
            if (cfgParams.Count != targetParams.Count)
            {
                return false;
            }
            // 参数匹配，-1表示通配符
            for (int i = 0; i < cfgParams.Count; i++)
            {
                if (cfgParams[i] != -1 && cfgParams[i] != targetParams[i])
                {
                    return false;
                }
            }
            UpdateQuestProgress(logicPlayer, questData, questData.progress + addNum);
            return true;
        }

        #endregion

        #region util

        /// <summary>
        /// 递归查询任务的所有子任务
        /// </summary>
        /// <param name="questCfg"></param>
        /// <param name="outList"></param>
        private void GetAllChildQuests(CfgQuest questCfg, List<CfgQuest> outList)
        {
            for (int i = 0; i < questCfg.ChildQuests.Count; i++)
            {
                int childQuestCid = questCfg.ChildQuests[i];
                CfgQuest childQuestCfg = TableCenter.quest.Get(childQuestCid);
                outList.Add(childQuestCfg);
                if (childQuestCfg.ChildQuests.Count > 0)
                {
                    GetAllChildQuests(childQuestCfg, outList);
                }
            }
        }

        #endregion
    }
}